/************************************************************************
 * SMLib - State Model Library
 * Copyright (C) 2012-2013 Ali Khalili (khalili_DOT_ir_@SIGN_gmail_DOT_com)
 * **********************************************************************
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License (LGPL) published 
 * by the Free Software Foundation; either version 2.1 of the License, or (at your
 * option) any later version. This program is distributed without any
 * warranty. See the GNU Lesser General Public License for more details. 
 * ***********************************************************************
 * File         :     SMLib\Utils\Matrix.cs
 * Description  :     This is used for simple solvers.
 * Change log   :     -Jan 2010:  First version
 * To Do        :     -improve performance
 ************************************************************************/
using System;
using System.Collections.Generic;
using System.Text;

namespace SMLib.Utils
{
   
    /// <summary>
    /// Interface for Squar matrix
    /// The CTMC structure (as a Squar Matrix A(n,n)) should implement interface to be used in MTBDD and other algorithms
    /// This is a very simpler interface to be used instead of IStateSpace, We usualy 
    /// assume that the currentState '0' is the initial currentState
    /// </summary>
    /// <typeparam name="TYPE">Type of elements in the squar matrix</typeparam>
    public interface ISqMatrix<TYPE>
    {
        double CTMCRate(int i, int j);
        TYPE this[int i, int j]
        {
            get;
            set;
        }

        int Size
        {
            get;
        }
    }

    /// <summary>
    /// [To Do: why not using IList??]
    /// </summary>
    public interface IVector
    {
        double getValue(int index);
        void setValue(int index, double value);
        double this[int index]
        {
            get;
            set;
        }
        int Size
        {
            get;
        }
    }


    /// <summary>
    /// Vector with double data: Sparse and Non-Sparse structure
    /// </summary>
    public class Vector : IVector
    {
        class element1D
        {
            public element1D(int index, double value)
            {
                this.index = index;
                this.value = value;
            }
            public int index;
            public double value;
        }

        int size;
        public int Size
        {
            get
            {
                return size;
            }
        }

        double mode = 0;

        /// <summary>
        /// Used in non-sparse representation
        /// </summary>
        double[] theVector;

        /// <summary>
        /// used in sparse representation
        /// </summary>
        List<element1D> sparceVector;

        /// <summary>
        /// use sparce or non-sparse representation
        /// </summary>
        bool useSparce;

        public Vector(int size, bool useSparce)
        {
            this.useSparce = useSparce;
            this.size = size;
            if (useSparce)
                sparceVector = new List<element1D>();
            else
                theVector = new double[size];


            //dimention = 1;
        }
        public Vector(int size)
        {
            this.size = size;
            this.useSparce = true;
            sparceVector = new List<element1D>();
        }

        public Vector(double[] n)
        {
            sparceVector = new List<element1D>();
            for (int i = 0; i < n.Length; i++)
                if (n[i] != mode)
                    sparceVector.Add(new element1D(i, n[i]));
            useSparce = true;

        }

        public double getValue(int index)
        {
            if (useSparce)
            {
                for (int i = 0; i < sparceVector.Count; i++)
                    if (((element1D)sparceVector[i]).index == index)
                        return ((element1D)sparceVector[i]).value;
                return mode;
            }
            else
            {
                return theVector[index];
            }
        }
        public double this[int index]
        {
            get
            {
                return getValue(index);
            }
            set
            {
                setValue(index, value);
            }
        }
        public void setValue(int index, double value)
        {
            if (useSparce)
            {
                for (int i = 0; i < sparceVector.Count; i++)
                    if (((element1D)sparceVector[i]).index == index)
                    {
                        if (value == mode)
                        {
                            sparceVector.RemoveAt(i);
                            return;
                        }
                        else
                        {
                            ((element1D)sparceVector[i]).value = value;
                            return;
                        }
                    }
                if (value != mode)
                    sparceVector.Add(new element1D(index, value));
            }
            else
            {
                theVector[index] = value;
            }
        }

        public void WriteToFile(string path)
        {
            string content = "[";
            for (int j = 0; j < Size; j++)
            {
                content += getValue(j) + "  ";
            }
            content += "]\r\n";

            System.IO.File.WriteAllText(path, content);
        }

    }


    /// <summary>
    /// Squar Matric with double data: Non-Sparse structure
    /// This is used in solving CTMCs in some iterative algorithms.
    /// </summary>
    public class Matrix : ISqMatrix<double>//, ICTMC_StateSpace//<object, double>
    {


        //int size;
        //double mode = 0;
        double[,] m;
        int r, c;

        public void changeMode1(double mode)
        {
            //this.mode = mode;
        }

        public Matrix(int rowDim, int colDim)
        {
            r = rowDim; c = colDim;
            m = new double[rowDim, colDim];
        }

        public double getValue(int row, int col)
        {
            return m[row, col];
        }

        public double this[int row, int col]
        {
            get
            {
                return m[row, col];
            }
            set
            {
                m[row, col] = value;
            }
        }

        public void setValue(int row, int col, double value)
        {
            m[row, col] = value;
        }

        public void WriteToFile(string path)
        {
            string content = "[";
            for (int i = 0; i < c; i++)
            {
                if (i > 0)
                    content += "\t,[";
                else
                    content += "\t[";
                for (int j = 0; j < r; j++)
                {
                    content += this[i, j] + "  ";
                }
                content += "]\r\n";
            }
            content += "\r\n]";
            System.IO.File.WriteAllText(path, content);
        }

        #region ICTMCMatrix Members

        public double CTMCRate(int i, int j)
        {
            return getValue(i, j);
        }

        public int Size
        {
            get { return m.Length; }
        }

        #endregion
    }
}
